/*    This file is part of rls.
 *
 *    Rls is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Lesser General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    Rls is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public License
 *    along with rls.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef RLS_H
#define RLS_H

/*
Include:
something with size_t
#include <rid.h>
#include <stdint.h>

#include <unfy/unfy.h>

#include <rls/rls.h>
*/


#ifndef STYLE_9
#include <rid.h>
#include <stdint.h>
#include <unfy/unfy.h>
#endif

typedef struct Rls_rule Rls_rule;
typedef struct Rls_srch Rls_srch;

typedef struct {
	Rls_rule *rules;
	Rls_srch *srchs;
	Unfy_recycle unfy;
} Rls_recycle;

typedef enum { RLS_SRCH, RLS_RUN } Rls_mode;
typedef Unfy_stat (*Rls_act)(Rls_mode mode, Rls_srch *srch, void *extra);

struct Rls_rule {
	Rls_rule *next;
	Unfy_term *head;
	void *dat;
	Rid id;

	union {
		Unfy_list *body;
		Rls_act act;
	} u;

	uint16_t size;
	uint16_t max_binds;
	uint8_t actable;
};

struct Rls_srch {
	Rls_srch *up;
        Unfy_term *term;
        Rls_rule *rule;
	Unfy_bind *lbind;
	Unfy_bind *rbind;
	Unfy_bind *nbind; /* name binds */
	Unfy_bind *fbind; /* final lbinds */
	Rls_srch **body;
	uint16_t num;
};

typedef enum {
	RLS_RSN_OKAY,
	RLS_RSN_END,
	RLS_RSN_LIMIT,
	RLS_RSN_UNFY,
} Rls_rsn;

typedef enum {
	RLS_DIF_SAME,
	RLS_DIF_ERR,
	RLS_DIF_NULL,
	/* check info for info */
	RLS_DIF_HEAD,
	RLS_DIF_BODY,
	RLS_DIF_ACTABLE,
	RLS_DIF_ACT,
} Rls_dif;

typedef struct {
	Unfy_info unfy;
	Unfy_bind *nbind;
	Unfy_term *term;
	Unfy_term *nterm;
	Rls_rule *rule;
	Rls_rsn rsn;
	unsigned  lull : 1; /* Stop if head fails to unify */
	unsigned miss : 1; /* Ignore successful unification of head */
} Rls_info;

typedef struct Rls_bndr Rls_bndr;

/* if stat is NULL then initialize rules on inability to find them */
typedef Rls_rule **(*Rls_bend)(const Unfy_term *term, Unfy_stat *stat,
			       void *extra);

typedef void (*Rls_dat_free)(void *dat, void *extra);

/* info */

int
rls_info_init(Rls_info *info, Unfy_term *term,
	      Rls_rule *rules, Rls_recycle *rec);

void
rls_info_dispose(Rls_info *info, Rls_recycle *rec);

/* void */
/* rls_info_change(Rls_info *info, Unfy_term *term, */
/* 		Rls_rule *rules, Rls_recycle *rec); */

/* void */
/* rls_info_next(Rls_info *info, Rls_recycle *rec); */

/* recycle */

void
rls_recycle_init(Rls_recycle *rec);

void
rls_recycle_empty(Rls_recycle *rec);

void
rls_recycle_rule(Rls_recycle *rec, Rls_rule *rule,
		 Rls_dat_free dat_free, void *extra);

void
rls_recycle_srch(Rls_recycle *rec, Rls_srch *srch);

/* rule */

int
rls_rule_add(Rls_rule **rule, const Rid id, Unfy_term *head,
	     Unfy_list *body, void *dat, Rls_recycle *rec);

int
rls_rule_add_actable(Rls_rule **rule, const Rid id, Unfy_term *head,
		     Rls_act act, void *dat, Rls_recycle *rec);

Rls_dif
rls_rule_same(Unfy_info *info, Rls_rule *left, Rls_rule *right,
	      Rls_recycle *rec);

Unfy_stat
rls_rule_query(Rls_info *info, Rls_recycle *rec);

/* srch */

Unfy_stat
rls_srch_limit(Rls_srch **srch_ref, Unfy_term *term, Rls_rule *rules,
	       int *limit, Rls_bend bend, Rls_info *info, void *extra,
	       Rls_recycle *rec);

Unfy_stat
rls_srch(Rls_srch **srch_ref, Unfy_term *term, Rls_rule *rules,
	 Rls_bend bend, Rls_info *info, void *extra, Rls_recycle *rec);

void
rls_srch_next(Rls_srch **srch);

int
rls_srch_same_next(Rls_srch **left, Rls_srch **right);

Rls_dif
rls_srch_same(Unfy_info *info, Rls_srch **left, Rls_srch **right,
	      Rls_recycle *rec);

Unfy_stat
rls_srch_run(Rls_srch *srch, void *extra);

#endif
